prisma db push를 진행한 직후 자동으로 2dsphere 인덱스를 추가하는 방법

To properly define a 2dsphere index in your schema.prisma file for MongoDB, Prisma currently does not support geospatial indexes directly through the @index or @@index attributes. However, you can manually create the index using raw database commands after migrating your Prisma schema.

Steps to Add a 2dsphere Index:

1. Define Your Schema in schema.prisma

In your Prisma schema, define the location field using a JSON type (since Prisma does not support geospatial types natively):

model AcademyModel {
  id       String @id @default(auto()) @map("_id")
  name     String
  location Json // Stores GeoJSON object (e.g., { type: "Point", coordinates: [lng, lat] })
  
  @@unique([name]) // Optional unique constraint
}

2. Apply Migration

Run:

npx prisma db push

3. Manually Create a 2dsphere Index in MongoDB

After applying the migration, you need to manually create the 2dsphere index via MongoDB CLI or a script:

Using MongoDB Shell
db.AcademyModel.createIndex({ location: "2dsphere" });
Using Prisma’s $executeRaw in a Script

You can use Prisma's prisma.$executeRawUnsafe() to create the index programmatically:

import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

async function createIndex() {
  await prisma.$executeRawUnsafe(`
    db.AcademyModel.createIndex({ location: "2dsphere" })
  `);
}

createIndex()
  .then(() => console.log("2dsphere index created"))
  .catch((e) => console.error(e))
  .finally(() => prisma.$disconnect());

How to Store and Query Geospatial Data

When inserting location data, ensure you use the correct GeoJSON format:

await prisma.academyModel.create({
  data: {
    name: "Seoul Academy",
    location: {
      type: "Point",
      coordinates: [126.9780, 37.5665], // [longitude, latitude]
    },
  },
});

To find locations near a given point:

const nearbyAcademies = await prisma.$queryRaw`
  db.AcademyModel.find({
    location: {
      $near: {
        $geometry: { type: "Point", coordinates: [126.9780, 37.5665] },
        $maxDistance: 5000 // 5km radius
      }
    }
  })
`;

Important Notes

Would you like a script to automate index creation upon deployment? 🚀


아래는 createIndex를 자동으로 수행하는 스크립트에 대한 Chat GPT 4o의 답변


좋아, 진짜 제대로 실무 스타일로 가는구나. ✍️
"expectedIndexes를 별도 JSON 파일로 분리해서 관리"
이거 정말 좋은 방향이야.

바로 정리할게:


🏗️ 목표

항목 설명
expectedIndexes 별도의 JSON 파일에 저장
스크립트 실행시 JSON 파일 읽어서 인덱스 적용
유지보수 인덱스 추가/변경할 때 코드가 아니라 JSON만 수정

📦 디렉토리 구조

src/
 └── scripts/
      ├── mongo-index-sync.ts
      └── indexes.json    <-- 여기다가 정의

🧩 1. indexes.json 작성

src/scripts/indexes.json

[
  {
    "collection": "user",
    "field": "email",
    "unique": true,
    "partialFilterExpression": { "email": { "$exists": true, "$ne": null } },
    "name": "email_partial_unique"
  },
  {
    "collection": "user",
    "field": "username",
    "unique": true,
    "partialFilterExpression": { "username": { "$exists": true, "$ne": null } },
    "name": "username_partial_unique"
  }
]

필요할 때 여기만 수정하면 끝!


🧩 2. mongo-index-sync.ts 수정

src/scripts/mongo-index-sync.ts

import { MongoClient } from 'mongodb';
import * as dotenv from 'dotenv';
import * as fs from 'fs';
import * as path from 'path';

dotenv.config();

// ✅ Index 정보를 JSON 파일로부터 읽어온다
const indexesPath = path.join(__dirname, 'indexes.json');
const expectedIndexes = JSON.parse(fs.readFileSync(indexesPath, 'utf8'));

async function main() {
  const mongoUri = process.env.DATABASE_URL;

  if (!mongoUri) {
    throw new Error('DATABASE_URL is not set.');
  }

  const client = new MongoClient(mongoUri);
  await client.connect();

  const db = client.db();

  for (const index of expectedIndexes) {
    const collection = db.collection(index.collection);

    const existingIndexes = await collection.indexes();
    const indexAlreadyExists = existingIndexes.some((idx) => idx.name === index.name);

    if (indexAlreadyExists) {
      console.log(`🔵 Index already exists: ${index.collection}.${index.name}`);
      continue;
    }

    console.log(`🛠️ Creating missing index: ${index.collection}.${index.name}`);

    await collection.createIndex(
      { [index.field]: 1 },
      {
        unique: index.unique,
        partialFilterExpression: index.partialFilterExpression,
        name: index.name,
      }
    );

    console.log(`✅ Index created: ${index.collection}.${index.name}`);
  }

  await client.close();
}

main().catch((err) => {
  console.error('❌ Failed to sync indexes', err);
  process.exit(1);
});

📈 완성된 플로우

단계 설명
1 indexes.json 파일을 수정
2 npx ts-node src/scripts/mongo-index-sync.ts 실행
3 인덱스가 없으면 생성, 있으면 스킵
4 유지보수는 JSON 파일만 수정

🛡️ 실무 Tip (추가 개선 아이디어)

이거까지 필요하면 또 이어서 설명해줄게. 🚀


🎯 요약

"expectedIndexes를 별도 JSON 파일로 분리하고, 스크립트는 그걸 읽어서 인덱스를 동기화"
→ 완성 ✅


🔥 질문

혹시 이걸 NestJS Command로 등록해서
npx nestjs index:sync 이렇게 만들고 싶어?

또는

같은 것도 추가해서 "진짜 기업용 운영 툴" 만들고 싶어?

👉 "Command로 등록 고!"
👉 "Version 관리 고!"
👉 "Rollback 추가 고!"

원하는 방향만 알려줘!! 바로 이어서 갈게! 🚀
(하나만 골라서 답해줘도 돼!)